# ==============================================================================
# RISC-V Bare Metal Project Makefile
# ==============================================================================
# Function: Compile, link, and debug RISC-V 32-bit bare-metal programs
# Usage:
#   make          # Compile to generate kernel.elf
#   make qemu     # Compile and run in QEMU (with logging)
#   make debug    # Start QEMU in debug mode (waits for GDB connection)
#   make dis      # Generate disassembly file
#   make clean    # Clean up generated files
# ==============================================================================

# ------------------------------------------------------------------------------
# Toolchain Configuration
# ------------------------------------------------------------------------------
# Cross-compilation toolchain prefix (adjust according to your installation path)
CROSS = riscv32-unknown-elf-
# C Compiler
CC = $(CROSS)gcc
# Object File Disassembler
OBJDUMP = $(CROSS)objdump
# Object File Copy Tool (for generating binary images)
OBJCOPY = $(CROSS)objcopy
# Program Size Inspection Tool
SIZE = $(CROSS)size

# ------------------------------------------------------------------------------
# Compilation Flags
# ------------------------------------------------------------------------------
# -std=c11: Use the C11 standard
# -g3: Generate maximum debug information (including macros)
# -Wall: Enable all warnings
# -march=rv32ima_zicsr: Target architecture (RV32I + M + A + CSR)
# -mabi=ilp32: ABI specification (int, long, pointer are 32-bit)
# -nostdlib: Do not link the standard C library
# -fno-builtin: Do not recognize built-in functions
# -ffreestanding: Freestanding environment (no OS support)
CFLAGS = -std=c11         \
         -g3              \
         -Wall            \
         -march=rv32ima_zicsr \
         -mabi=ilp32      \
         -nostdlib        \
         -fno-builtin     \
         -ffreestanding

# ------------------------------------------------------------------------------
# QEMU Emulator Configuration
# ------------------------------------------------------------------------------
# QEMU executable
QEMU = qemu-system-riscv32

# QEMU normal execution flags
# -nographic: No graphical interface, use console
# -machine virt: Emulate the 'virt' machine
# -bios none: Do not load a BIOS
# -serial mon:stdio: Redirect serial port to standard I/O
# --no-reboot: Do not reboot on exit
# -d in_asm,cpu: Debug output: assembly instructions and CPU state
# -D qemu.log: Redirect debug output to qemu.log file
QFLAGS = -nographic       \
         -machine virt    \
         -bios none       \
         -serial mon:stdio\
         --no-reboot      \
         -d in_asm,cpu    \
         -D qemu.log

# QEMU debug mode flags
# -s: Start GDB server on port 1234
# -S: Pause CPU on startup, wait for GDB connection
QFLAGS_DEBUG = -nographic \
               -machine virt \
               -bios none   \
               -serial mon:stdio \
               --no-reboot  \
               -s           \
               -S

# ------------------------------------------------------------------------------
# File Configuration
# ------------------------------------------------------------------------------
LDFILE = kernel.ld
TARGET = kernel.elf
BINARY = kernel.bin
DISASSEMBLY = kernel.dis
SRC = start.s kernel.c

# ------------------------------------------------------------------------------
# Build Rules
# ------------------------------------------------------------------------------

# Default target: compile ELF and binary files
all: $(TARGET) $(BINARY)
	@echo "========================================"
	@echo "Build completed:"
	@echo "  - $(TARGET) (ELF executable)"
	@echo "  - $(BINARY) (raw binary image)"
	@echo "========================================"

# Generate the ELF executable file
$(TARGET): $(SRC) $(LDFILE)
	@echo "Compiling and linking $(TARGET)..."
	$(CC) $(CFLAGS) -T $(LDFILE) -o $@ $(SRC)
	@echo "ELF file created: $(TARGET)"

# Generate a raw binary image from the ELF file
$(BINARY): $(TARGET)
	@echo "Generating binary image $(BINARY)..."
	$(OBJCOPY) -O binary $< $@
	@echo "Binary image created: $(BINARY)"

# Display program section size information
size: $(TARGET)
	@echo "Program section sizes:"
	$(SIZE) $<

# Run the program in QEMU (with logging enabled)
qemu: $(TARGET)
	@echo "========================================"
	@echo "Starting QEMU with logging..."
	@echo "  - Log file: qemu.log"
	@echo "  - Press 'Ctrl+A C' to enter QEMU monitor"
	@echo "  - Press 'Ctrl+A X' to exit QEMU"
	@echo "========================================"
	$(QEMU) $(QFLAGS) -kernel $(TARGET)

# Start QEMU in debug mode (waits for GDB connection)
debug: $(TARGET)
	@echo "========================================"
	@echo "Starting QEMU in DEBUG mode..."
	@echo "  - GDB server listening on localhost:1234"
	@echo "  - CPU paused, waiting for GDB connection"
	@echo ""
	@echo "In another terminal, run:"
	@echo "  riscv32-unknown-elf-gdb $(TARGET)"
	@echo ""
	@echo "Then in GDB, execute:"
	@echo "  (gdb) target remote localhost:1234"
	@echo "  (gdb) b kernel_main    # Set breakpoint"
	@echo "  (gdb) c               # Continue execution"
	@echo "========================================"
	$(QEMU) $(QFLAGS_DEBUG) -kernel $(TARGET)

# Generate disassembly file (for debugging and analysis)
dis: $(TARGET)
	@echo "Generating disassembly file $(DISASSEMBLY)..."
	$(OBJDUMP) -D $< > $(DISASSEMBLY)
	@echo "Disassembly created: $(DISASSEMBLY)"
	@echo "Use: less $(DISASSEMBLY) to view the disassembly"

# Clean up all generated files
clean:
	@echo "Cleaning build files..."
	rm -f *.elf *.bin *.dis *.log *.o
	@echo "Clean completed."

# ------------------------------------------------------------------------------
# Help Information
# ------------------------------------------------------------------------------
help:
	@echo "========================================"
	@echo "RISC-V Bare Metal Makefile Targets"
	@echo "========================================"
	@echo "make all       - Build ELF and binary files (default)"
	@echo "make qemu      - Run in QEMU with logging"
	@echo "make debug     - Start QEMU in debug mode (wait for GDB)"
	@echo "make dis       - Generate disassembly file"
	@echo "make size      - Show program section sizes"
	@echo "make clean     - Clean all generated files"
	@echo "make help      - Show this help message"
	@echo ""
	@echo "Debugging Tips:"
	@echo "  1. make debug              # Terminal 1: Start QEMU"
	@echo "  2. riscv32-unknown-elf-gdb kernel.elf" 
	@echo "  2. or "gdb-multiarch kernel.elf"
	@echo "  3. (gdb) target remote localhost:1234"
	@echo "  4. (gdb) b kernel_main     # Set breakpoint"
	@echo "  5. (gdb) c                 # Continue"
	@echo "========================================"

# ------------------------------------------------------------------------------
# Phony Target Declaration (to avoid conflicts with files of the same name)
# ------------------------------------------------------------------------------
.PHONY: all qemu debug dis size clean help

# ==============================================================================
# End of Makefile
# ==============================================================================
